package storage

import (
	"fmt"

	log "github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"
)

// Service 存储管理服务
type Service struct {
	connManager ConnManager
}

// ConnManager 连接管理器接口
type ConnManager interface {
	WithConn(fn func(*libvirt.Connect) error) error
}

// NewService 创建存储服务
func NewService(cm ConnManager) *Service {
	return &Service{connManager: cm}
}

// PoolInfo 存储池信息
type PoolInfo struct {
	UUID       string `json:"uuid"`
	Name       string `json:"name"`
	State      string `json:"state"`
	Capacity   uint64 `json:"capacity"`
	Allocation uint64 `json:"allocation"`
	Available  uint64 `json:"available"`
	Autostart  bool   `json:"autostart"`
	Persistent bool   `json:"persistent"`
	Type       string `json:"type"`
	XMLConfig  string `json:"xml_config,omitempty"`
}

// VolumeInfo 存储卷信息
type VolumeInfo struct {
	Name       string `json:"name"`
	Key        string `json:"key"`
	Path       string `json:"path"`
	Type       string `json:"type"`
	Capacity   uint64 `json:"capacity"`
	Allocation uint64 `json:"allocation"`
	Pool       string `json:"pool"`
	XMLConfig  string `json:"xml_config,omitempty"`
}

// CreatePoolSpec 创建存储池规格
type CreatePoolSpec struct {
	Name   string `json:"name" binding:"required"`
	Type   string `json:"type" binding:"required"` // dir, fs, netfs, disk, iscsi, logical, rbd
	Target string `json:"target"`                  // 目标路径
	Source string `json:"source,omitempty"`        // 源设备/路径
}

// CreateVolumeSpec 创建存储卷规格
type CreateVolumeSpec struct {
	Name     string `json:"name" binding:"required"`
	Capacity uint64 `json:"capacity" binding:"required"` // 字节
	Format   string `json:"format"`                      // qcow2, raw, vmdk
	Pool     string `json:"pool" binding:"required"`
}

// ListPools 列出所有存储池
func (s *Service) ListPools(includeInactive bool) ([]PoolInfo, error) {
	var pools []PoolInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		flags := libvirt.CONNECT_LIST_STORAGE_POOLS_ACTIVE
		if includeInactive {
			flags |= libvirt.CONNECT_LIST_STORAGE_POOLS_INACTIVE
		}

		storagePools, err := conn.ListAllStoragePools(flags)
		if err != nil {
			return fmt.Errorf("failed to list storage pools: %w", err)
		}

		for _, pool := range storagePools {
			info, err := s.getPoolInfo(&pool, false)
			if err != nil {
				log.Warnf("Failed to get pool info: %v", err)
				continue
			}
			pools = append(pools, *info)
			pool.Free()
		}
		return nil
	})

	return pools, err
}

// GetPool 获取存储池详情（通过名称）
func (s *Service) GetPool(name string, includeXML bool) (*PoolInfo, error) {
	var poolInfo *PoolInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(name)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		poolInfo, err = s.getPoolInfo(pool, includeXML)
		return err
	})

	return poolInfo, err
}

// GetPoolByUUID 通过UUID获取存储池详情
func (s *Service) GetPoolByUUID(uuid string, includeXML bool) (*PoolInfo, error) {
	var poolInfo *PoolInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByUUIDString(uuid)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		poolInfo, err = s.getPoolInfo(pool, includeXML)
		return err
	})

	return poolInfo, err
}

// CreatePool 创建存储池
func (s *Service) CreatePool(spec *CreatePoolSpec) (*PoolInfo, error) {
	poolXML := s.buildPoolXML(spec)

	var poolInfo *PoolInfo
	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.StoragePoolDefineXML(poolXML, 0)
		if err != nil {
			return fmt.Errorf("failed to define storage pool: %w", err)
		}
		defer pool.Free()

		// 构建存储池（如需创建目录等）
		if err := pool.Build(0); err != nil {
			log.Warnf("Failed to build storage pool: %v (may be ok for some types)", err)
		}

		// 启动存储池
		if err := pool.Create(0); err != nil {
			return fmt.Errorf("failed to start storage pool: %w", err)
		}

		poolInfo, err = s.getPoolInfo(pool, false)
		log.Infof("Storage pool %s created and started", spec.Name)
		return err
	})

	return poolInfo, err
}

// StartPool 启动存储池（通过名称）
func (s *Service) StartPool(name string) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(name)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		if err := pool.Create(0); err != nil {
			return fmt.Errorf("failed to start storage pool: %w", err)
		}

		log.Infof("Storage pool %s started", name)
		return nil
	})
}

// StartPoolByUUID 通过UUID启动存储池
func (s *Service) StartPoolByUUID(uuid string) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByUUIDString(uuid)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		if err := pool.Create(0); err != nil {
			return fmt.Errorf("failed to start storage pool: %w", err)
		}

		name, _ := pool.GetName()
		log.Infof("Storage pool %s (UUID: %s) started", name, uuid)
		return nil
	})
}

// StopPool 停止存储池（通过名称）
func (s *Service) StopPool(name string) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(name)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		if err := pool.Destroy(); err != nil {
			return fmt.Errorf("failed to stop storage pool: %w", err)
		}

		log.Infof("Storage pool %s stopped", name)
		return nil
	})
}

// StopPoolByUUID 通过UUID停止存储池
func (s *Service) StopPoolByUUID(uuid string) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByUUIDString(uuid)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		if err := pool.Destroy(); err != nil {
			return fmt.Errorf("failed to stop storage pool: %w", err)
		}

		name, _ := pool.GetName()
		log.Infof("Storage pool %s (UUID: %s) stopped", name, uuid)
		return nil
	})
}

// DeletePool 删除存储池（通过名称）
func (s *Service) DeletePool(name string, deleteVolumes bool) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(name)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		// 停止池（如果正在运行）
		active, _ := pool.IsActive()
		if active {
			if err := pool.Destroy(); err != nil {
				log.Warnf("Failed to stop pool before delete: %v", err)
			}
		}

		// 删除池（如果需要删除存储）
		if deleteVolumes {
			if err := pool.Delete(0); err != nil {
				log.Warnf("Failed to delete pool storage: %v", err)
			}
		}

		// 取消定义
		if err := pool.Undefine(); err != nil {
			return fmt.Errorf("failed to undefine storage pool: %w", err)
		}

		log.Infof("Storage pool %s deleted", name)
		return nil
	})
}

// DeletePoolByUUID 通过UUID删除存储池
func (s *Service) DeletePoolByUUID(uuid string, deleteVolumes bool) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByUUIDString(uuid)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		name, _ := pool.GetName()

		// 停止池（如果正在运行）
		active, _ := pool.IsActive()
		if active {
			if err := pool.Destroy(); err != nil {
				log.Warnf("Failed to stop pool before delete: %v", err)
			}
		}

		// 删除池（如果需要删除存储）
		if deleteVolumes {
			if err := pool.Delete(0); err != nil {
				log.Warnf("Failed to delete pool storage: %v", err)
			}
		}

		// 取消定义
		if err := pool.Undefine(); err != nil {
			return fmt.Errorf("failed to undefine storage pool: %w", err)
		}

		log.Infof("Storage pool %s (UUID: %s) deleted", name, uuid)
		return nil
	})
}

// RefreshPool 刷新存储池（通过名称）
func (s *Service) RefreshPool(name string) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(name)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		if err := pool.Refresh(0); err != nil {
			return fmt.Errorf("failed to refresh storage pool: %w", err)
		}

		log.Infof("Storage pool %s refreshed", name)
		return nil
	})
}

// RefreshPoolByUUID 通过UUID刷新存储池
func (s *Service) RefreshPoolByUUID(uuid string) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByUUIDString(uuid)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		if err := pool.Refresh(0); err != nil {
			return fmt.Errorf("failed to refresh storage pool: %w", err)
		}

		name, _ := pool.GetName()
		log.Infof("Storage pool %s (UUID: %s) refreshed", name, uuid)
		return nil
	})
}

// ListVolumes 列出存储池中的所有卷（通过存储池名称）
func (s *Service) ListVolumes(poolName string) ([]VolumeInfo, error) {
	var volumes []VolumeInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(poolName)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		vols, err := pool.ListAllStorageVolumes(0)
		if err != nil {
			return fmt.Errorf("failed to list volumes: %w", err)
		}

		for _, vol := range vols {
			info, err := s.getVolumeInfo(&vol, poolName, false)
			if err != nil {
				log.Warnf("Failed to get volume info: %v", err)
				continue
			}
			volumes = append(volumes, *info)
			vol.Free()
		}
		return nil
	})

	return volumes, err
}

// ListVolumesByPoolUUID 通过存储池UUID列出存储池中的所有卷
func (s *Service) ListVolumesByPoolUUID(poolUUID string) ([]VolumeInfo, error) {
	var volumes []VolumeInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByUUIDString(poolUUID)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		poolName, _ := pool.GetName()

		vols, err := pool.ListAllStorageVolumes(0)
		if err != nil {
			return fmt.Errorf("failed to list volumes: %w", err)
		}

		for _, vol := range vols {
			info, err := s.getVolumeInfo(&vol, poolName, false)
			if err != nil {
				log.Warnf("Failed to get volume info: %v", err)
				continue
			}
			volumes = append(volumes, *info)
			vol.Free()
		}
		return nil
	})

	return volumes, err
}

// GetVolume 获取存储卷详情
func (s *Service) GetVolume(poolName, volumeName string, includeXML bool) (*VolumeInfo, error) {
	var volInfo *VolumeInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(poolName)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		vol, err := pool.LookupStorageVolByName(volumeName)
		if err != nil {
			return fmt.Errorf("volume not found: %w", err)
		}
		defer vol.Free()

		volInfo, err = s.getVolumeInfo(vol, poolName, includeXML)
		return err
	})

	return volInfo, err
}

// CreateVolume 创建存储卷
func (s *Service) CreateVolume(spec *CreateVolumeSpec) (*VolumeInfo, error) {
	volumeXML := s.buildVolumeXML(spec)

	var volInfo *VolumeInfo
	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(spec.Pool)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		vol, err := pool.StorageVolCreateXML(volumeXML, 0)
		if err != nil {
			return fmt.Errorf("failed to create volume: %w", err)
		}
		defer vol.Free()

		volInfo, err = s.getVolumeInfo(vol, spec.Pool, false)
		log.Infof("Volume %s created in pool %s", spec.Name, spec.Pool)
		return err
	})

	return volInfo, err
}

// DeleteVolume 删除存储卷
func (s *Service) DeleteVolume(poolName, volumeName string) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		pool, err := conn.LookupStoragePoolByName(poolName)
		if err != nil {
			return fmt.Errorf("storage pool not found: %w", err)
		}
		defer pool.Free()

		vol, err := pool.LookupStorageVolByName(volumeName)
		if err != nil {
			return fmt.Errorf("volume not found: %w", err)
		}
		defer vol.Free()

		if err := vol.Delete(0); err != nil {
			return fmt.Errorf("failed to delete volume: %w", err)
		}

		log.Infof("Volume %s deleted from pool %s", volumeName, poolName)
		return nil
	})
}

// getPoolInfo 从 libvirt.StoragePool 提取信息
func (s *Service) getPoolInfo(pool *libvirt.StoragePool, includeXML bool) (*PoolInfo, error) {
	name, err := pool.GetName()
	if err != nil {
		return nil, err
	}

	uuid, err := pool.GetUUIDString()
	if err != nil {
		return nil, err
	}

	info, err := pool.GetInfo()
	if err != nil {
		return nil, err
	}

	autostart, _ := pool.GetAutostart()
	persistent, _ := pool.IsPersistent()
	active, _ := pool.IsActive()

	state := "inactive"
	if active {
		state = "active"
	}

	poolInfo := &PoolInfo{
		UUID:       uuid,
		Name:       name,
		State:      state,
		Capacity:   info.Capacity,
		Allocation: info.Allocation,
		Available:  info.Available,
		Autostart:  autostart,
		Persistent: persistent,
		Type:       poolStateToString(info.State),
	}

	if includeXML {
		xmlDesc, err := pool.GetXMLDesc(0)
		if err != nil {
			log.Warnf("Failed to get XML for pool %s: %v", name, err)
		} else {
			poolInfo.XMLConfig = xmlDesc
		}
	}

	return poolInfo, nil
}

// getVolumeInfo 从 libvirt.StorageVol 提取信息
func (s *Service) getVolumeInfo(vol *libvirt.StorageVol, poolName string, includeXML bool) (*VolumeInfo, error) {
	name, err := vol.GetName()
	if err != nil {
		return nil, err
	}

	key, err := vol.GetKey()
	if err != nil {
		return nil, err
	}

	path, err := vol.GetPath()
	if err != nil {
		return nil, err
	}

	info, err := vol.GetInfo()
	if err != nil {
		return nil, err
	}

	volInfo := &VolumeInfo{
		Name:       name,
		Key:        key,
		Path:       path,
		Type:       volumeTypeToString(info.Type),
		Capacity:   info.Capacity,
		Allocation: info.Allocation,
		Pool:       poolName,
	}

	if includeXML {
		xmlDesc, err := vol.GetXMLDesc(0)
		if err != nil {
			log.Warnf("Failed to get XML for volume %s: %v", name, err)
		} else {
			volInfo.XMLConfig = xmlDesc
		}
	}

	return volInfo, nil
}

// buildPoolXML 构建存储池 XML
func (s *Service) buildPoolXML(spec *CreatePoolSpec) string {
	xml := fmt.Sprintf(`<pool type='%s'>
  <name>%s</name>
  <target>
    <path>%s</path>
  </target>`, spec.Type, spec.Name, spec.Target)

	if spec.Source != "" {
		xml += fmt.Sprintf(`
  <source>
    <device path='%s'/>
  </source>`, spec.Source)
	}

	xml += "\n</pool>"
	return xml
}

// buildVolumeXML 构建存储卷 XML
func (s *Service) buildVolumeXML(spec *CreateVolumeSpec) string {
	format := spec.Format
	if format == "" {
		format = "qcow2"
	}

	return fmt.Sprintf(`<volume>
  <name>%s</name>
  <capacity unit='bytes'>%d</capacity>
  <target>
    <format type='%s'/>
  </target>
</volume>`, spec.Name, spec.Capacity, format)
}

// poolStateToString 转换池状态为字符串
func poolStateToString(state libvirt.StoragePoolState) string {
	switch state {
	case libvirt.STORAGE_POOL_INACTIVE:
		return "inactive"
	case libvirt.STORAGE_POOL_BUILDING:
		return "building"
	case libvirt.STORAGE_POOL_RUNNING:
		return "running"
	case libvirt.STORAGE_POOL_DEGRADED:
		return "degraded"
	case libvirt.STORAGE_POOL_INACCESSIBLE:
		return "inaccessible"
	default:
		return "unknown"
	}
}

// volumeTypeToString 转换卷类型为字符串
func volumeTypeToString(volType libvirt.StorageVolType) string {
	switch volType {
	case libvirt.STORAGE_VOL_FILE:
		return "file"
	case libvirt.STORAGE_VOL_BLOCK:
		return "block"
	case libvirt.STORAGE_VOL_DIR:
		return "dir"
	case libvirt.STORAGE_VOL_NETWORK:
		return "network"
	case libvirt.STORAGE_VOL_NETDIR:
		return "netdir"
	case libvirt.STORAGE_VOL_PLOOP:
		return "ploop"
	default:
		return "unknown"
	}
}
